今天加緊腳步把ProjectTracker.vue的資料也存到firebase去
先處理firestore database的部分,新增一個集合來存ProjectTracker.vue的資料
集合的名稱各位可以自行決定,如果是跟著做專案進度追蹤的可以參考以下的欄位設定
我是先將集合命名成projects,然後設定欄位
專案會包括的元素有專案名稱(string),其中的子任務(array),判斷專案是否完成(boolean)
而每個子任務會包含的元素有任務名稱(string),判斷任務是否完成(boolean)
將包含子任務的陣列名稱設定為subtasks,並在裡面新增物件型別的元素
一個map中可以同時包含多個欄位設定
所以我們要存子任務的話,先用map將任務名稱和是否完長的判斷狀態包在一起
在陣列中建立多個map就是建立多個子任務
完成firestore database中集合的建立後,就來處理程式碼吧
先到ProjectTracker.vue
的<script setup>
區域,先刪除所有LocalStorage 邏輯
刪掉這些程式碼
// === 讀取 LocalStorage ===
const savedProjects = localStorage.getItem("projects")
if (savedProjects) {
projects.value = JSON.parse(savedProjects)
}
// === 監聽 projects 變化並存入 LocalStorage ===
watch(projects, (newVal) => {
localStorage.setItem("projects", JSON.stringify(newVal))
}, { deep: true })
然後import這些
import { ref, onMounted } from 'vue'
import { db } from '@/firebase'
import { collection, getDocs, addDoc, updateDoc, deleteDoc, doc } from "firebase/firestore"
添加這幾段程式碼
// 讀取 Firestore 專案資料
async function loadProjects() {
const querySnapshot = await getDocs(collection(db, "projects"))
projects.value = querySnapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}))
}
// 一開始載入資料
onMounted(() => {
loadProjects()
})
要注意 const querySnapshot = await getDocs(collection(db, "projects"))
這裡的"projects"是你自己設定的集合名稱
接著修改function
// 讀取 Firestore 專案資料
async function loadProjects() {
const querySnapshot = await getDocs(collection(db, "projects"))
projects.value = querySnapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}))
}
// 新增專案
async function addProject(title) {
if (title.trim() !== '') {
const newProj = {
title,
done: false,
subtasks: []
}
const docRef = await addDoc(collection(db, "projects"), newProj)
projects.value.push({ id: docRef.id, ...newProj })
newProject.value = ''
}
}
// 新增子任務
async function addSubtask(projectIndex, text) {
if (text.trim() === '') return
const project = projects.value[projectIndex]
const updatedSubtasks = [...project.subtasks, { text, done: false }]
const docRef = doc(db, "projects", project.id)
await updateDoc(docRef, { subtasks: updatedSubtasks })
project.subtasks = updatedSubtasks
project.newSubtask = ''
}
// 切換子任務完成狀態
async function toggleSubtask(projectIndex, subtaskIndex) {
const project = projects.value[projectIndex]
const subtasks = [...project.subtasks]
subtasks[subtaskIndex].done = !subtasks[subtaskIndex].done
await updateDoc(doc(db, "projects", project.id), { subtasks })
project.subtasks = subtasks
}
// 刪除專案
async function deleteProject(pIndex) {
const id = projects.value[pIndex].id
await deleteDoc(doc(db, "projects", id))
projects.value.splice(pIndex, 1)
}
// 刪除子任務
async function deleteSubtask(pIndex, sIndex) {
const project = projects.value[pIndex]
const updatedSubtasks = [...project.subtasks]
updatedSubtasks.splice(sIndex, 1)
await updateDoc(doc(db, "projects", project.id), { subtasks: updatedSubtasks })
project.subtasks = updatedSubtasks
}
// 計算進度
function projectProgress(project) {
if (project.subtasks.length === 0) return 0
const doneCount = project.subtasks.filter(s => s.done).length
return Math.round((doneCount / project.subtasks.length) * 100)
}
我記得<template>
沒修改甚麼,各位修改完<script setup>
區域的程式應該能在測試頁面
看到剛才新建的專案,以防萬一我還是附上<script setup>
和<template>
區的程式碼
<script setup>
import { ref, onMounted } from 'vue'
import { db } from '@/firebase'
import { collection, getDocs, addDoc, updateDoc, deleteDoc, doc } from "firebase/firestore"
// 儲存專案清單
const projects = ref([])
// 專案輸入框
const newProject = ref('')
// 讀取 Firestore 專案資料
async function loadProjects() {
const querySnapshot = await getDocs(collection(db, "projects"))
projects.value = querySnapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}))
}
// 一開始載入資料
onMounted(() => {
loadProjects()
})
// 新增專案
async function addProject(title) {
if (title.trim() !== '') {
const newProj = {
title,
done: false,
subtasks: []
}
const docRef = await addDoc(collection(db, "projects"), newProj)
projects.value.push({ id: docRef.id, ...newProj })
newProject.value = ''
}
}
// 新增子任務
async function addSubtask(projectIndex, text) {
if (text.trim() === '') return
const project = projects.value[projectIndex]
const updatedSubtasks = [...project.subtasks, { text, done: false }]
const docRef = doc(db, "projects", project.id)
await updateDoc(docRef, { subtasks: updatedSubtasks })
project.subtasks = updatedSubtasks
project.newSubtask = ''
}
// 切換子任務完成狀態
async function toggleSubtask(projectIndex, subtaskIndex) {
const project = projects.value[projectIndex]
const subtasks = [...project.subtasks]
subtasks[subtaskIndex].done = !subtasks[subtaskIndex].done
await updateDoc(doc(db, "projects", project.id), { subtasks })
project.subtasks = subtasks
}
// 刪除專案
async function deleteProject(pIndex) {
const id = projects.value[pIndex].id
await deleteDoc(doc(db, "projects", id))
projects.value.splice(pIndex, 1)
}
// 刪除子任務
async function deleteSubtask(pIndex, sIndex) {
const project = projects.value[pIndex]
const updatedSubtasks = [...project.subtasks]
updatedSubtasks.splice(sIndex, 1)
await updateDoc(doc(db, "projects", project.id), { subtasks: updatedSubtasks })
project.subtasks = updatedSubtasks
}
// 計算進度
function projectProgress(project) {
if (project.subtasks.length === 0) return 0
const doneCount = project.subtasks.filter(s => s.done).length
return Math.round((doneCount / project.subtasks.length) * 100)
}
</script>
<template>
<div class="project-tracker">
<h2>📊 專案進度追蹤</h2>
<!-- 新增專案 -->
<div class="input-box">
<input
v-model="newProject"
placeholder="輸入專案名稱..."
@keyup.enter="addProject(newProject); newProject=''"
/>
<button @click="addProject(newProject); newProject=''">新增專案</button>
</div>
<!-- 專案清單 -->
<div v-for="(project, pIndex) in projects" :key="pIndex" class="project-box">
<h3>{{ project.title }}
<!-- 刪除專案按鈕 -->
<button class="deletProjectButton" @click="deleteProject(pIndex)">❌ 刪除專案</button>
</h3>
<!-- 進度條 -->
<div class="progress-bar">
<div
class="progress"
:style="{ width: projectProgress(project) + '%' }"
></div>
</div>
<p>{{ projectProgress(project) }}%</p>
<!-- 新增子任務 -->
<div class="input-box">
<input
v-model="project.newSubtask"
placeholder="輸入子任務..."
@keyup.enter="addSubtask(pIndex, project.newSubtask); project.newSubtask=''"
/>
<button @click="addSubtask(pIndex, project.newSubtask); project.newSubtask=''">新增子任務</button>
</div>
<!-- 子任務清單 -->
<ul class="task-list">
<li
v-for="(subtask, sIndex) in project.subtasks"
:key="sIndex"
:class="{ done: subtask.done }"
>
<span @click="toggleSubtask(pIndex, sIndex)">
<input
type="checkbox"
v-model="subtask.done"
/>{{ subtask.text }}</span>
<!-- 刪除子任務按鈕 -->
<button class="deletSubtaskButton" @click="deleteSubtask(pIndex, sIndex)">🗑 刪除</button>
</li>
</ul>
</div>
</div>
</template>
這是我目前測試網頁的畫面和資料庫的畫面
好的終於將資料都成功轉到firebase了
祝各位中秋節快樂~
各位明天見~